from datetime import datetime
from extension import db
import time
import secrets
import string

def generate_random():
    """生成唯一6位大写字母数字组合（2位随机前缀 + 4位时间戳编码）"""
    # 生成2位随机大写字母前缀
    prefix = ''.join(secrets.choice(string.ascii_uppercase) for _ in range(2))
    # 获取当前时间戳（从2023年1月1日开始的秒数）
    epoch_start = 1672531200  # 2023-01-01 00:00:00 UTC
    timestamp = int(time.time() - epoch_start)
    # 限制时间戳为4位36进制能表示的最大值：36^4 - 1 = 1679615
    max_timestamp = 36 ** 4 - 1
    timestamp = timestamp % max_timestamp  # 确保时间戳在范围内
    # 内联实现整数转36进制编码，固定4位长度
    charset = string.ascii_lowercase + string.digits
    encoded_time = ''
    for _ in range(4):  # 固定4位，不足补0
        timestamp, remainder = divmod(timestamp, 36)
        encoded_time = charset[remainder] + encoded_time
    # 转换为大写
    encoded_time = encoded_time.upper()
    return f"{prefix}{encoded_time}"




class User(db.Model):
    """用户信息表模型"""
    __tablename__ = 'users'

    id = db.Column(db.BigInteger, primary_key=True, comment='用户ID')
    username = db.Column(db.String(50), nullable=False, unique=True,default=generate_random, comment='用户名(默认六位随机字母数字组合)')
    password = db.Column(db.String(100), default='123456',comment='密码(默认123456)')
    email = db.Column(db.String(100), unique=True, comment='电子邮箱')
    phone = db.Column(db.String(20), unique=True, comment='手机号码')
    nickname = db.Column(db.String(50), nullable=False, comment='昵称')
    avatar = db.Column(db.String(255), nullable=False, default='/static/avatars/default.png',comment='头像URL')
    openid = db.Column(db.String(100), unique=True, nullable=False, comment='第三方开放ID(如微信openid)')
    role = db.Column(db.SmallInteger, default=0, comment='用户角色: 0-普通用户, 1-管理员')
    create_time = db.Column(db.DateTime, nullable=False, default=datetime.now(),comment='创建时间')
    update_time = db.Column(db.DateTime, nullable=False, default=datetime.now(),onupdate=lambda: datetime.now(), comment='更新时间')
    status = db.Column(db.SmallInteger, default=0, comment='用户状态: 0-正常, 1-禁用')
    last_login_time = db.Column(db.DateTime, comment='最后登录时间')

    # 关系定义
    created_rules = db.relationship('RuleConfig',backref=db.backref('creator', lazy='selectin'), foreign_keys='RuleConfig.creator_id',lazy='dynamic')  # 用户创建的自定义规则
    created_rooms = db.relationship('Room',backref=db.backref('creator', lazy='selectin'),foreign_keys='Room.creator_id',lazy='dynamic')  # 用户创建的房间
    room_players = db.relationship('RoomPlayer', backref='user', lazy='selectin')  # 用户参与的房间
    dealt_rounds = db.relationship(
        'Round',
        foreign_keys='Round.dealer_id',
        backref=db.backref('dealer', lazy='selectin'),
        lazy='dynamic'
    )  # 作为庄家的轮次
    won_rounds = db.relationship(
        'Round',
        foreign_keys='Round.winner_id',
        backref=db.backref('winner', lazy='selectin'),
        lazy='dynamic'
    )  # 作为赢家的轮次
    operations = db.relationship(
        'RoundOperation',
        foreign_keys='RoundOperation.operator_id',
        backref=db.backref('operator', lazy='selectin'),
        lazy='dynamic'
    )  # 作为操作者的记录
    target_operations = db.relationship(
        'RoundOperation',
        foreign_keys='RoundOperation.target_id',
        backref=db.backref('target', lazy='selectin'),
        lazy='dynamic'
    )  # 作为目标的记录

    __table_args__ = (
        db.Index('idx_email', 'email'),
        db.Index('idx_phone', 'phone'),
        db.Index('idx_openid', 'openid'),
        db.Index('idx_status_role', 'status', 'role'),
        {'comment': '用户信息表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "openid": self.openid,
            "username": self.username,
            "nickname": self.nickname,
            "avatar": self.avatar,
            "role": self.role,
            "status": self.status,
            "create_time": self.create_time.strftime('%Y-%m-%d %H:%M:%S') if self.create_time else None,
            "last_login_time": self.last_login_time.strftime('%Y-%m-%d %H:%M:%S') if self.last_login_time else None
        }


class RuleConfig(db.Model):
    """规则配置表模型"""
    __tablename__ = 'rule_configs'

    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='规则ID')
    rule_name = db.Column(db.String(50), nullable=False, comment='规则名称')
    rule_type = db.Column(db.SmallInteger, nullable=False, comment='规则类型: 1-系统预设, 2-用户自定义')
    rule_content = db.Column(db.JSON, nullable=False, comment='规则内容(番型、倍数等)')
    is_default = db.Column(db.SmallInteger, nullable=False, default=0,
                           comment='是否默认规则: 0-否, 1-是')
    creator_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=True,  # 系统规则可无创建者
                           comment='创建者ID(用户自定义规则时使用)')
    create_time = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(), comment='创建时间')
    update_time = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(),
                            onupdate=lambda: datetime.now(), comment='更新时间')

    # 关系定义
    rooms = db.relationship('Room', backref='rule_config', lazy='selectin')  # 使用该规则的房间

    __table_args__ = (
        db.Index('idx_rule_type', 'rule_type'),
        db.Index('idx_creator_id', 'creator_id'),
        {'comment': '规则配置表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "rule_name": self.rule_name,
            "rule_type": self.rule_type,
            "rule_content": self.rule_content,
            "is_default": self.is_default,
            "creator_id": self.creator_id,
            "create_time": self.create_time.strftime('%Y-%m-%d %H:%M:%S')
        }


class Room(db.Model):
    """房间表模型"""
    __tablename__ = 'rooms'

    id = db.Column(db.BigInteger, primary_key=True,  comment='房间ID')
    room_code = db.Column(db.String(50), unique=True, nullable=False,comment='房间码')
    creator_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=False, comment='创建者ID')
    name = db.Column(db.String(50), default='默认房间', comment='房间名称')  # 补充默认值
    # rule_config_id = db.Column(db.BigInteger, db.ForeignKey('rule_configs.id'), nullable=False,comment='规则配置ID')
    rule_config_id = db.Column(db.BigInteger, db.ForeignKey('rule_configs.id'), comment='规则配置ID')
    max_players = db.Column(db.Integer, nullable=False, default=4, comment='最大玩家数')
    total_games = db.Column(db.Integer, nullable=False, default=0, comment='总局数')
    current_game = db.Column(db.Integer, nullable=False, default=0, comment='当前局数')
    create_time = db.Column(db.DateTime, nullable=False, default=datetime.now(), comment='创建时间')
    start_time = db.Column(db.DateTime, comment='游戏开始时间')
    end_time = db.Column(db.DateTime, comment='游戏结束时间')
    update_time = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(),onupdate=lambda: datetime.now(), comment='更新时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1,comment='房间状态: 1-等待中, 2-游戏中, 3-已结束')
    # 新增字段：当前成员列表（JSON格式存储用户ID数组）
    members = db.Column(db.JSON, default=[])  # 示例: [1, 2, 3]

    # 关系定义
    players = db.relationship('RoomPlayer', backref='room', lazy='selectin',
                              cascade="all, delete-orphan")  # 房间内的玩家（级联删除）
    rounds = db.relationship('Round', backref='room', lazy='dynamic',
                             cascade="all, delete-orphan")  # 房间内的轮次（级联删除）

    __table_args__ = (
        db.Index('idx_creator_id', 'creator_id'),
        db.Index('idx_status', 'status'),
        db.Index('idx_create_time', 'create_time'),
        {'comment': '房间表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "room_code": self.room_code,
            "name": self.name,
            "creator_id": self.creator_id,
            "rule_config_id": self.rule_config_id,
            "max_players": self.max_players,
            "current_game": self.current_game,
            "total_games": self.total_games,
            "status": self.status,
            "create_time": self.create_time.strftime('%Y-%m-%d %H:%M:%S'),
            "start_time": self.start_time.strftime('%Y-%m-%d %H:%M:%S') if self.start_time else None
        }


class RoomPlayer(db.Model):
    """房间玩家关联表模型"""
    __tablename__ = 'room_players'

    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='ID')
    room_id = db.Column(db.BigInteger, db.ForeignKey('rooms.id'), nullable=False, comment='房间ID')
    user_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=False, comment='用户ID')
    nickname = db.Column(db.String(50), nullable=False, comment='玩家昵称(快照)')
    avatar = db.Column(db.String(255), default='/static/avatars/default.png', comment='玩家头像(快照)')
    score = db.Column(db.Integer, nullable=False, default=0, comment='当前分数')
    is_owner = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否房主: 0-否, 1-是')
    join_time = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(), comment='加入时间')
    leave_time = db.Column(db.DateTime, comment='离开时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1,
                       comment='玩家状态: 1-在线, 2-离线, 3-已离开')

    __table_args__ = (
        db.UniqueConstraint('room_id', 'user_id', name='unique_room_user'),
        db.Index('idx_user_id', 'user_id'),
        db.Index('idx_room_status', 'room_id', 'status'),
        {'comment': '房间玩家关联表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "room_id": self.room_id,
            "user_id": self.user_id,
            "nickname": self.nickname,
            "avatar": self.avatar,
            "score": self.score,
            "is_owner": self.is_owner,
            "status": self.status,
            "join_time": self.join_time.strftime('%Y-%m-%d %H:%M:%S')
        }


class Round(db.Model):
    """轮次对局表模型"""
    __tablename__ = 'rounds'
    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='轮次ID')
    room_id = db.Column(db.String(36), db.ForeignKey('rooms.id'), nullable=False, comment='房间ID')
    round_number = db.Column(db.Integer, nullable=False, comment='游戏局数')
    score_detail = db.Column(db.JSON, default=dict, comment='分数详情(JSON格式，包含各用户分数变动、规则影响等)')
    user1_score = db.Column(db.Integer, nullable=True, default=None, comment='用户1结束分数')
    user2_score = db.Column(db.Integer, nullable=True, default=None, comment='用户2结束分数')
    user3_score = db.Column(db.Integer, nullable=True, default=None, comment='用户3结束分数')
    user4_score = db.Column(db.Integer, nullable=True, default=None, comment='用户4结束分数')
    dealer_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=False, comment='庄家ID')
    winner_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), comment='赢家ID')
    start_time = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), comment='开始时间')
    end_time = db.Column(db.DateTime, comment='结束时间')
    status = db.Column(db.SmallInteger, nullable=False, default=1, comment='游戏状态: 1-进行中, 2-已结束')

    # 关系定义
    operations = db.relationship('RoundOperation', backref='round', lazy='selectin', cascade="all, delete-orphan")

    __table_args__ = (
        db.Index('idx_room_status', 'room_id', 'status'),
        db.Index('idx_dealer_id', 'dealer_id'),
        db.Index('idx_winner_id', 'winner_id'),
        db.Index('idx_start_time', 'start_time'),
        {'comment': '轮次对局记录表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "room_id": self.room_id,
            "round_number": self.round_number,
            "score_detail": self.score_detail,
            "user1_score": self.user1_score,
            "user2_score": self.user2_score,
            "user3_score": self.user3_score,
            "user4_score": self.user4_score,
            "dealer_id": self.dealer_id,
            "winner_id": self.winner_id,
            "status": self.status,
            "start_time": self.start_time.strftime('%Y-%m-%d %H:%M:%S'),
            "end_time": self.end_time.strftime('%Y-%m-%d %H:%M:%S') if self.end_time else None
        }


class RoundOperation(db.Model):
    """轮次操作记录表模型"""
    __tablename__ = 'round_operations'

    id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='操作ID')
    round_id = db.Column(db.BigInteger, db.ForeignKey('rounds.id'), nullable=False, comment='轮次ID')
    operator_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=False, comment='操作者ID')
    target_id = db.Column(db.BigInteger, db.ForeignKey('users.id'), nullable=True, comment='目标玩家ID')  # 允许为空
    operation_type = db.Column(db.SmallInteger, nullable=False,
                               comment='操作类型: 1-胡牌, 2-自摸, 3-点炮, 4-杠牌, 5-计分调整')
    score_change = db.Column(db.Integer, nullable=False, default=0, comment='分数变化')
    before_score = db.Column(db.Integer, nullable=False, comment='操作前分数')
    after_score = db.Column(db.Integer, nullable=False, comment='操作后分数')
    operation_detail = db.Column(db.JSON, comment='操作详情(番型、倍数等)')
    operation_time = db.Column(db.DateTime, nullable=False, default=lambda: datetime.now(), comment='操作时间')

    __table_args__ = (
        db.Index('idx_round_id', 'round_id'),
        db.Index('idx_operator_id', 'operator_id'),
        db.Index('idx_operation_time', 'operation_time'),
        {'comment': '轮次操作记录表'}
    )

    def to_dict(self):
        return {
            "id": self.id,
            "round_id": self.round_id,
            "operator_id": self.operator_id,
            "target_id": self.target_id,
            "operation_type": self.operation_type,
            "score_change": self.score_change,
            "operation_time": self.operation_time.strftime('%Y-%m-%d %H:%M:%S'),
            "operation_detail": self.operation_detail
        }
'''
三、关系定义潜在问题
RoomPlayer 与 User 的冗余字段
RoomPlayer 存储了 nickname 和 avatar 作为 “快照”，但未同步更新机制。若用户修改昵称 / 头像，房间内的快照不会更新，可能导致数据不一致。
建议：
要么删除快照字段，直接通过关联关系从 User 表获取实时数据；
要么在用户修改信息时，通过触发器或业务逻辑同步更新所有关联的 RoomPlayer 记录。
lazy 参数使用不一致
部分关系使用 lazy='dynamic'（返回查询对象），部分使用 lazy='selectin'（预加载），需根据实际查询场景统一逻辑：
一对多关系中，若需频繁过滤子查询（如 user.created_rooms.filter(...)），用 dynamic；
若只需加载全部关联数据（如 room.players），用 selectin 更高效。
外键约束缺失级联策略
例如 Round.dealer_id 关联 User.id，但未设置 ondelete 策略。若用户被删除，关联的 Round 记录会因外键约束报错。
建议：根据业务需求补充级联策略，如 db.ForeignKey('users.id', ondelete='SET NULL')（用户删除后设为 NULL）。
四、索引设计优化
冗余索引
User 表中对 email、phone、openid 既设了 unique=True（自动创建唯一索引），又手动加了普通索引，属于冗余。
建议：删除手动创建的普通索引，保留唯一约束即可。
缺少联合索引
例如查询 “状态为正常的管理员用户”（status=0 AND role=1），User 表的 idx_status_role 复合索引合理，但其他场景可能缺失：
Room 表若需频繁查询 “未结束的房间”（status=1 OR status=2），可加 status 索引；
RoundOperation 若需按 “轮次 + 操作类型” 查询，可加 (round_id, operation_type) 联合索引。
五、其他细节
RuleConfig.creator_id 允许为 NULL
系统预设规则（rule_type=1）的 creator_id 可为 NULL，设计合理，但需在业务层确保 “用户自定义规则（rule_type=2）必须有 creator_id”。
Round 表的 game_process 和 round_result
用 JSON 类型存储游戏过程和结果，适合灵活扩展，但需注意：
避免存储过大数据（影响查询性能）；
关键字段（如胜负、分数）建议单独拆分为列（便于索引和统计）。
to_dict 方法遗漏字段
部分模型的 to_dict 未包含所有常用字段（如 RuleConfig.update_time、Room.end_time），可能影响前端数据展示。
建议：根据接口需求补充必要字段，或动态生成（如用 dataclass 或序列化库替代硬编码）。
'''